package com.libgdxbar.pvzlikegame.entities;

import com.badlogic.gdx.graphics.Camera;
import com.badlogic.gdx.graphics.g2d.Batch;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.Disposable;
import com.badlogic.gdx.utils.IntMap;
import com.libgdxbar.pvzlikegame.render.BatchRenderAgent;
import com.libgdxbar.pvzlikegame.render.Job;
import com.libgdxbar.pvzlikegame.render.RenderAgent;
import com.libgdxbar.pvzlikegame.render.ShapeRenderAgent;
import org.libgdxbar.projects.interfaces.GameRunnable;
import org.libgdxbar.projects.interfaces.renderer.BatchRenderable;
import org.libgdxbar.projects.interfaces.renderer.Renderable;
import org.libgdxbar.projects.interfaces.renderer.ShapeRenderable;

/**
 * <h3>EntityGroup类负责管理游戏中的所有实体对象</h3>
 * 包括它们的渲染和更新，它实现了Disposable接口，以便在游戏资源不再需要时释放资源
 */
public final class EntityGroup implements Disposable {

	// 使用Singleton模式确保只有一个EntityGroup实例
	@SuppressWarnings("GDXJavaStaticResource")
	private static EntityGroup instance;
	// 存储所有实体、可渲染作业和可更新对象的数组
	public IntMap<BaseEntity> _all = new IntMap<>();
	public Array<Job> _renderable = new Array<>();
	public Array<GameRunnable> _updateable = new Array<>();
	// 用于渲染的Batch和ShapeRenderer
	public Batch batch = new SpriteBatch();
	public ShapeRenderer shapeRenderer = new ShapeRenderer() {{
		setAutoShapeType(true);
	}};
	// 渲染代理对象，用于批量渲染和形状渲染
	private BatchRenderAgent batchRenderAgent = new BatchRenderAgent(batch);
	private ShapeRenderAgent shapeRenderAgent = new ShapeRenderAgent(shapeRenderer);

	/**
	 * 防止外部通过构造函数创建EntityGroup实例，确保单例模式的实现。
	 */
	private EntityGroup() throws RuntimeException {
		if (instance != null) {
			throw new RuntimeException("单例实体，不允许重复创建");
		}
	}

	/**
	 * 获取EntityGroup的单例实例
	 *
	 * @return EntityGroup的实例
	 */
	public static synchronized EntityGroup getInstance() {
		if (instance == null) {
			instance = new EntityGroup();
		}
		return instance;
	}

	/**
	 * 向EntityGroup中添加一个实体对象
	 *
	 * @param baseEntity 要添加的实体对象
	 */
	public void add(BaseEntity baseEntity) {
		// 防止重复添加实体
		if (_all.containsKey(baseEntity.id)) {
			return;
		}
		if (baseEntity instanceof Renderable) {
			Renderable renderable = (Renderable) baseEntity;
			if (baseEntity instanceof ShapeRenderable) {
				_renderable.add(new Job(renderable, shapeRenderAgent));
			}
			if (baseEntity instanceof BatchRenderable) {
				_renderable.add(new Job(renderable, batchRenderAgent));
			}
		}
		if (baseEntity instanceof GameRunnable) {
			GameRunnable gameRunnable = (GameRunnable) baseEntity;
			_updateable.add(gameRunnable);
		}
		_all.put(baseEntity.id, baseEntity);
	}

	/**
	 * 从EntityGroup中移除一个实体对象
	 *
	 * @param baseEntity 要移除的实体对象
	 */
	public void remove(BaseEntity baseEntity) {
		if (baseEntity instanceof Renderable) {
			Renderable renderable = (Renderable) baseEntity;
			for (int i = 0; i < _renderable.size; i++) {
				Job job = _renderable.get(i);
				if (job.renderable != renderable) {
					continue;
				}
				_renderable.removeIndex(i);
				break;
			}
		}
		if (baseEntity instanceof GameRunnable) {
			GameRunnable gameRunnable = (GameRunnable) baseEntity;
			_updateable.removeValue(gameRunnable, true);
		}
		_all.remove(baseEntity.id);
	}

	/**
	 * 渲染所有实体对象
	 *
	 * @param camera 渲染使用的摄像机
	 */
	public void render(Camera camera) {
		// 按照Z轴值对可渲染作业进行排序，确保渲染顺序正确
		_renderable.sort((o1, o2) -> Float.compare(o1.renderable.z(), o2.renderable.z()));

		// 当前活跃的渲染代理
		RenderAgent activeAgent = null;

		// 遍历所有可渲染作业
		for (Job job : _renderable) {
			final RenderAgent agent = job.agent;

			// 如果当前作业的渲染代理与活跃代理不同
			if (agent != activeAgent) {
				// 如果有活跃代理，结束其渲染
				if (activeAgent != null) {
					activeAgent.end();
				}

				// 更新活跃代理为当前作业的渲染代理
				activeAgent = agent;

				// 设置渲染代理的视图相机
				activeAgent.setView(camera);

				// 开始渲染
				activeAgent.begin();
			}

			// 使用当前活跃代理渲染当前作业
			agent.render(job.renderable);
		}

		// 如果有活跃代理，结束其渲染
		if (activeAgent != null) {
			activeAgent.end();
		}
	}

	/**
	 * 更新所有实体对象的状态
	 *
	 * @param delta 自上次更新以来的时间间隔
	 */
	public void update(float delta) {
		for (GameRunnable gameRunnable : _updateable) {
			gameRunnable.run(delta);
		}
	}

	/**
	 * 释放所有实体对象的资源
	 */
	@Override
	public void dispose() {
		for (BaseEntity baseEntity : _all.values()) {
			if (baseEntity instanceof Disposable) {
				Disposable disposable = (Disposable) baseEntity;
				disposable.dispose();
			}
		}
		_all.clear();
		_renderable.clear();
		_updateable.clear();
	}
}
